﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace Saper
{
    public class SaperGame : Panel
    {
        public long GameTime; // общее время игры
        public int height,width,mines; //ширина поля, его высота и кол-во мин
        private Cell[,] field;	// массив клеток   
        private enum stateType { EMPTY, LIGHT, FLAG, DOWN, MINED }; //возможные состояния клетки

        

        class Cell : PictureBox //: EventArgs
        {
            SaperGame saper;
            public bool mined; // есть ли мина?
            public int mineCount; // счетчик мин, находящихся в соседних клетках
            private int x,y,w; //размеры клетки
            public stateType state; //состояние клетки
            public int Number;
            public bool checkk = false;

            public Cell(int x, int y, int w, SaperGame saper)
            {
                this.saper = saper;
                this.x = x;
                this.y = y;
                this.w = w;
                this.Image = global::Saper.Properties.Resources.empty;
                this.Location = new System.Drawing.Point(x, y);
                this.Size = new System.Drawing.Size(w, w);
                this.TabIndex = 1;
                this.TabStop = false;
                this.Visible = true;
                MouseEnter += new System.EventHandler(this.cell__MouseEnter);
                MouseLeave += new System.EventHandler(this.cell__MouseLeave);
                MouseClick += new System.Windows.Forms.MouseEventHandler(this.cell_MouseClick);
            }

            public void repaint()
            {
                switch (state)
                {
                    case stateType.EMPTY:
                        this.Image = global::Saper.Properties.Resources.empty;
                        break;
                    case stateType.LIGHT:
                        this.Image = global::Saper.Properties.Resources.light;
                        break;
                    case stateType.DOWN:
                        switch (this.mineCount)
                        {
                            case 0: this.Image = global::Saper.Properties.Resources.number; break;
                            case 1: this.Image = global::Saper.Properties.Resources.number1; break;
                            case 2: this.Image = global::Saper.Properties.Resources.number2; break;
                            case 3: this.Image = global::Saper.Properties.Resources.number3; break;
                            case 4: this.Image = global::Saper.Properties.Resources.number4; break;
                            case 5: this.Image = global::Saper.Properties.Resources.number5; break;
                            case 6: this.Image = global::Saper.Properties.Resources.number6; break;
                            case 7: this.Image = global::Saper.Properties.Resources.number7; break;
                            case 8: this.Image = global::Saper.Properties.Resources.number8; break;
                            default: break;
                        }
                        break;

                    case stateType.FLAG:
                        this.Image = global::Saper.Properties.Resources.flag;
                        break;
                    case stateType.MINED:
                        this.Image = global::Saper.Properties.Resources.bomb;
                        break;
                    default:
                        break;
                }
            }


            public void cell__MouseEnter(object sender, EventArgs e)
            {
                if (state == stateType.EMPTY)
                {
                    this.state = stateType.LIGHT;
                    this.repaint();
                }
            }

            public void cell__MouseLeave(object sender, EventArgs e)
            {
                if (state == stateType.LIGHT)
                {
                    this.state = stateType.EMPTY;
                    this.repaint();
                }


            }

            public void cell_MouseClick(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    if ((state == stateType.LIGHT) || (state == stateType.FLAG))
                    {
                        if (mined == false)
                        {///////////////////////////////////////////////////////////////////

                            int j = Convert.ToInt16(Math.Truncate(Convert.ToDouble(Number / saper.width)));
                            int i = Number - j * saper.width;
                            if (saper.WinWin(i, j) == true)
                            {
                                Win();
                            }

                            if (mineCount == 0)
                            {
                                saper.OpenNearCells(i, j);
                            }
                            state = stateType.DOWN;
                            repaint();
                        }

                        else
                        {
                            Form1.timer1.Stop();
                            saper.OpenCells();
                            state = stateType.MINED;
                            repaint();
                            MessageBox.Show("Вы проиграли!", "Конец");
                        }
                    }
                }
                else
                {
                    if (state == stateType.LIGHT)
                    {
                        state = stateType.FLAG;////////////////////////////////////////////////
                        repaint();
                        int j = Convert.ToInt16(Math.Truncate(Convert.ToDouble(Number / saper.width)));
                        int i = Number - j * saper.width;
                        if (Form1.mineleft>0)
                            Form1.mineleft--;
                        Form1.label2.Text = "Осталось мин:"+Form1.mineleft;
                        if (saper.WinWin(i,j)==true)
                        {
                            Win();

                            
                        }
                    }
                }

            }

            private void Win()
            {
                Form1.timer1.Stop();
                string[,] mas = new string[3, 3];
                try
                {
                    ReadScores("scores.txt", mas);

                    MessageBox.Show("Победа!", "Юхуу!");
                    switch (Form1.difficulty)
                    {
                        case Difficulty.NEWBIE:
                            string name;
                            if (Convert.ToInt32(mas[0, 2]) > Form1.time)
                            {
                                InputBox.Input("Новый рекорд!", "Введите ваше имя", out name);
                                name.Replace(" ","_");
                                mas[0, 2] = Convert.ToString(Form1.time);
                                mas[0, 1] = name;
                                WriteScores("scores.txt", mas);
                            }
                            break;
                        case Difficulty.AMATOR:
                            if (Convert.ToInt32(mas[1, 2]) > Form1.time)
                            {
                                InputBox.Input("Новый рекорд!", "Введите ваше имя", out name);
                                name.Replace(" ", "_");
                                mas[1, 2] = Convert.ToString(Form1.time);
                                mas[1, 1] = name;
                                WriteScores("scores.txt", mas);


                            }
                            break;
                        case Difficulty.PROFI:
                            if (Convert.ToInt32(mas[2, 2]) > Form1.time)
                            {
                                InputBox.Input("Новый рекорд!", "Введите ваше имя", out name);
                                name.Replace(" ", "_");
                                mas[2, 2] = Convert.ToString(Form1.time);
                                mas[2, 1] = name;
                                WriteScores("scores.txt", mas);
                            }
                            break;
                        case Difficulty.SPECIAL:


                            break;
                        default:
                            break;
                    }

                    saper.OpenCells();
                }
                catch
                {
                    MessageBox.Show("Ошибка открытия файла", "Ошибка");
                }
            
            }

            private void ReadScores(string filename, string [,] mas)
            {
                int counter = 0;
                string line;
                System.IO.StreamReader file =
                new System.IO.StreamReader(@filename, System.Text.Encoding.Default, false);
                while ((line = file.ReadLine()) != null)
                {
                    string[] s = line.Split();
                    for (int i = 0; i < 3; i++)
                    {
                        mas[counter, i] = s[i];
                        

                    }
                    counter++;
                }
                file.Close();
            }

            private void WriteScores(string filename, string[,] mas)
            {
                System.IO.StreamWriter file =
            new System.IO.StreamWriter(@filename,false,Encoding.Default);
                    for (int i = 0; i < 3; i++)
                    {
                        for (int j = 0; j < 3; j++)
                        {
                             file.Write(mas[i, j]+" ");


                        }
                        file.Write("\n");
                    }
                file.Close();
            }


            public void OpenCell()
            {
                if (mined == false)
                {
                    state = stateType.DOWN;
                    repaint();
                }
                else
                {
                    state = stateType.MINED;
                    repaint();
                }

            }



        }// конец клетки

        public SaperGame(int height, int width, int mines)
        { // конструктор поля игры
            
            this.Size = new System.Drawing.Size(width * 20, height * 20);
            if (width <= 15) { this.width = width; }
            else { this.width = 15; }

            if (height <= 15) { this.height = height; }
            else { this.height = 15; }

            Form1.mineleft = mines;
            Form1.label2.Text = "Осталось мин:" + mines;

            if ((mines <= this.height * this.width - 5) && (mines != 0)) { this.mines = mines; }
            else { this.mines = this.height * this.width - 5; }

            field = new Cell[this.width, this.height];
            int xx = 0; int yy = 0;
            for (int i = 0; i < this.width; i++)
            {
                for (int j = 0; j < this.height; j++)
                {
                    field[i, j] = new Cell(xx, yy, 20, this);
                    field[i, j].Parent = this;
                    xx = xx + 20;
                }
                yy = yy + 20;
                xx = 0;
            }

            Random r = new Random(); // случайная генерация

            List<int> ar = new List<int>();
            for (int i = 0; i < width*height; i++)
                ar.Add(i);

            int[] result = new int[this.mines];
            for (int i = 0; i < this.mines; i++)
            {
                int pos = r.Next(0, ar.Count);
                result[i] = ar[pos];
                ar.RemoveAt(pos);
            }

            foreach (int num in result)
            {
                int j = Convert.ToInt16(Math.Truncate(Convert.ToDouble(num/ width)));
                int i = num - j * width;
                field[i, j].mined = true;
                field[i, j].Number = num;
            }


            for (int i = 0; i < this.width; i++)
            {
                for (int j = 0; j < this.height; j++)
                {
                    field[i, j].Number = j*width+i;

                    if (field[i, j].mined == false)
                    { 
                        if ((i - 1) >= 0)
                        {
                            if (((j - 1) >= 0) && (field[i - 1, j - 1].mined == true)) { field[i, j].mineCount++; }
                            if ((field[i - 1, j].mined == true)) { field[i, j].mineCount++; }
                            if (((j + 1) < this.height) && (field[i - 1, j + 1].mined == true)) { field[i, j].mineCount++; }
                        }
                        if ((i + 1) < this.width)
                        {
                            if (((j - 1) >= 0) && (field[i + 1, j - 1].mined == true)) { field[i, j].mineCount++; }
                            if ((field[i + 1, j].mined == true)) { field[i, j].mineCount++; }
                            if (((j + 1) < this.height) && (field[i + 1, j + 1].mined == true)) { field[i, j].mineCount++; }
                        }
                        if (((j - 1) >= 0) && (field[i, j - 1].mined == true)) { field[i, j].mineCount++; }
                        if (((j + 1) < this.height) && (field[i, j + 1].mined == true)) { field[i, j].mineCount++; }
                    }
                }
            }
        }// конец конструктора поля игры

        public void OpenCells()
        {     // Открывает все клетки

            for (int i = 0; i < this.width; i++)
            {
                for (int j = 0; j < this.height; j++)
                {
                    field[i, j].OpenCell();
                }
            }
        }

        public void OpenNearCells(int i, int j)
        { // рекурсивная процедура открытия соседних клеток
            if (field[i, j] != null)
            {
                if (field[i, j].checkk != true)
                {
                    field[i, j].checkk = true;
                    if ((i - 1) >= 0)
                    {
                        if ((j - 1) >= 0)
                        {
                            field[i - 1, j - 1].OpenCell();
                            if (field[i - 1, j - 1].mineCount == 0)
                                OpenNearCells(i - 1, j - 1);
                        }

                        field[i - 1, j].OpenCell();
                        if (field[i - 1, j].mineCount == 0)
                            OpenNearCells(i - 1, j);


                        if ((j + 1) < this.height)
                        {
                            field[i - 1, j + 1].OpenCell();
                            if (field[i - 1, j + 1].mineCount == 0)
                                OpenNearCells(i - 1, j + 1);

                        }
                    }

                    if ((i + 1) < this.width)
                    {
                        if ((j - 1) >= 0)
                        {
                            field[i + 1, j - 1].OpenCell();
                            if (field[i + 1, j - 1].mineCount == 0)
                                OpenNearCells(i + 1, j - 1);
                        }

                        field[i + 1, j].OpenCell();
                        if (field[i + 1, j].mineCount == 0)
                            OpenNearCells(i + 1, j);


                        if ((j + 1) < this.height) 
                        { field[i + 1, j + 1].OpenCell();
                         if (field[i + 1, j+1].mineCount == 0)
                            OpenNearCells(i + 1, j+1);
                        }
                    }

                    if ((j - 1) >= 0)
                    {
                        field[i, j - 1].OpenCell();
                        if (field[i, j - 1].mineCount == 0)
                            OpenNearCells(i, j - 1);
                    }

                    if ((j + 1) < this.height)
                    { field[i, j + 1].OpenCell();
                    if (field[i, j + 1].mineCount == 0)
                        OpenNearCells(i, j + 1);
                    }
                }
                

            }
        }

        public bool WinWin(int i, int j)
        {
            if ((field[i, j].state == field[i, j].state) && (field[i, j].mined == true))
                this.mines--;
            if (this.mines == 0)
            {
                for (i = 0; i < this.width; i++)
                {
                    for (j = 0; j < this.height; j++)
                    {
                        if ((field[i, j].state == stateType.FLAG) && (field[i, j].mined == false))
                        {
                            return false;
                        }
                    }
                }

                return true;
            }

            else
                return false;
        }




    }
}


